#include "swpsimulationcasedocument.h"

#include "../documents/data/simgraphicdata.h"

#include "../editors/items/graphicitemcommon.h"
#include "../editors/items/isimitem.h"
#include "../editors/items/swpactivityconnectorgraphicitem.h"
#include "../editors/items/swpactivitygraphicitem.h"
#include "../editors/items/swpendpointgraphicitem.h"
#include "../editors/items/swpjoingraphicitem.h"
#include "../editors/items/swpmergegraphicitem.h"
#include "../editors/items/swpstartpointgraphicitem.h"
#include "../editors/items/swpstartpointgraphicitem.h"

#include "../editors/items/swpsimactivityconnectorgraphicitem.h"
#include "../editors/items/swpsimactivitygraphicitem.h"
#include "../editors/items/swpsimdecisiongraphicitem.h"
#include "../editors/items/swpsimendpointgraphicitem.h"
#include "../editors/items/swpsimjoingraphicitem.h"
#include "../editors/items/swpsimmergegraphicitem.h"
#include "../editors/items/swpsimsplitgraphicitem.h"
#include "../editors/items/swpsimstartpointgraphicitem.h"
#include "../editors/items/swpsimswimlanegraphicitem.h"

#include "../editors/items/swpsplitgraphicitem.h"
#include "../editors/items/swpswimlanegraphicitem.h"

#include "../utils/undomanager.h"

#include "swpprojectdocument.h"

#include <coremimetypes.h>
#include <gdmodelquerymaker.h>
#include <ieditoritem.h>
#include <mimetypemanager.h>

#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>

using namespace core;
using namespace swp;

typedef QPair<ISimItem*, bool> SimValue;
typedef QSharedPointer<core::IDocument> Document;

SwpSimulationCaseDocument::SwpSimulationCaseDocument(const QString& name,
    const MimeType& mimeType,
    const QSharedPointer<core::IContainerDocument>& container,
    bool isFuture) : SwpAbstractLinkedDocument(name, mimeType, container,
        isFuture),
        m_simData(new SimGraphicData())
{
    const int width = QApplication::desktop()->width();
    const int height = QApplication::desktop()->height();

    m_simData->setSceneRect(0, 0, width, height);

    connect(m_simData, SIGNAL(dataChanged()),
        this, SLOT(makeDirty()));
    connect(m_simData, SIGNAL(validChanged(bool)),
        this, SLOT(handleValidChange(bool)));

    m_simData->addSnapToGridException(SWP_SIM_SWIMLANE_ITEM);

    m_data = m_simData;

    m_valid = true;
}

SwpSimulationCaseDocument::~SwpSimulationCaseDocument()
{

}

QList<MimeType> SwpSimulationCaseDocument::linksTo() const
{
    QList<MimeType> ret;

    ret.append(MimeTypeManager::getInstance()->mimeType(
        ACTIVITY_DIAGRAM_MIMETYPE));

    return ret;
}

void SwpSimulationCaseDocument::linksUpdated(bool projectIsOpening)
{
    const bool isValid = !m_links.isEmpty() ? m_links.first()->isValid() :
        true;

    if (!projectIsOpening && isValid)
    {
        UndoManager::getInstance()->clearStack(m_simData);

        m_simData->clearSimpath();

        m_simData->setIgnoreSnapFlag(true);

        GDModelQueryMaker queryMaker(*m_simData);

        const QList<IGraphicEditorItem* > simActivities =
            queryMaker.getItems(SWP_SIM_ACTIVITY_ITEM);
        QList<IEditorItem* > _simActivities;

        QHash<QUuid, QPair<ISimItem*, bool> > simActivitiesMapping;

        foreach (IGraphicEditorItem* simActivity, simActivities)
        {
            _simActivities << dynamic_cast<IEditorItem* >(simActivity);

            ISimItem* simItem = dynamic_cast<ISimItem* >(simActivity);

            Q_ASSERT(simItem != 0); // can't happen

            simActivitiesMapping[simItem->originId()] =
                QPair<ISimItem*, bool>(simItem, false);
        }

        m_simData->clearData(_simActivities);

        foreach(const Document& link, m_links)
        {
            GraphicData* data = dynamic_cast<GraphicData* >(link->data());

            Q_ASSERT(data != 0); // shouldn't happen

            m_simData->setGraphicPalette(data->graphicPalette());

            m_simData->setSceneRect(data->sceneRect());

            QHash<QUuid, QUuid> idMapping;

            const QList<IGraphicEditorItem*> items = data->graphicItems();

            foreach (IGraphicEditorItem* item, items)
            {
                IGraphicEditorItem* _item = 0;
                ISimItem* simItem = 0;

                switch (item->type())
                {
                    case SWP_ACTIVITY_ITEM:
                    {
                        SwpActivityGraphicItem* activity =
                            dynamic_cast<SwpActivityGraphicItem*>(item);

                        Q_ASSERT(activity != 0); // bad type

                        if (simActivitiesMapping.contains(activity->id()))
                        {
                            SwpSimActivityGraphicItem* _activity =
                                dynamic_cast<SwpSimActivityGraphicItem* >(
                                simActivitiesMapping[activity->id()].first);

                            // remove old and invalid connections
                            _activity->connectionsRefreshed();

                            _activity->setPos(activity->pos());
                            _activity->repositionMarks();

                            _item = _activity;
                            simActivitiesMapping[activity->id()].second =
                                true;
                        }
                        else
                        {
                            _item = new SwpSimActivityGraphicItem(
                                activity);
                        }
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[activity->id()] = _item->id();
                        break;
                    }
                    case SWP_DECISION_ITEM:
                    {
                        SwpDecisionGraphicItem* decision =
                            dynamic_cast<SwpDecisionGraphicItem*>(item);
                        Q_ASSERT(decision != 0); // bad type
                        SwpSimDecisionGraphicItem* _decision =
                            new SwpSimDecisionGraphicItem(decision);
                        _decision->setParentDocumentData(m_simData);
                        _decision->initYesNo(decision);
                        _item = _decision;
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[decision->id()] = _item->id();
                        break;
                    }
                    case SWP_SWIMLANE_ITEM:
                    {
                        SwpSwimlaneGraphicItem* swimlane =
                            dynamic_cast<SwpSwimlaneGraphicItem*>(item);
                        Q_ASSERT(swimlane != 0); // bad type
                        _item = new SwpSimSwimlaneGraphicItem(
                            swimlane);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[swimlane->id()] = _item->id();
                        break;
                    }
                    case SWP_JOIN_ITEM:
                    {
                        SwpJoinGraphicItem* join =
                            dynamic_cast<SwpJoinGraphicItem*>(item);
                        Q_ASSERT(join != 0); // bad type
                        _item = new SwpSimJoinGraphicItem(join);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[join->id()] = _item->id();
                        break;
                    }
                    case SWP_SPLIT_ITEM:
                    {
                        SwpSplitGraphicItem* split =
                            dynamic_cast<SwpSplitGraphicItem*>(item);
                        Q_ASSERT(split != 0); // bad type
                        _item = new SwpSimSplitGraphicItem(split);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[split->id()] = _item->id();
                        break;
                    }
                    case SWP_START_POINT_ITEM:
                    {
                        SwpStartPointGraphicItem* startPoint =
                            dynamic_cast<SwpStartPointGraphicItem*>(item);
                        Q_ASSERT(startPoint != 0); // bad type
                        _item = new SwpSimStartPointGraphicItem(
                            startPoint);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[startPoint->id()] = _item->id();
                        break;
                    }
                    case SWP_END_POINT_ITEM:
                    {
                        SwpEndPointGraphicItem* endPoint =
                            dynamic_cast<SwpEndPointGraphicItem*>(item);
                        Q_ASSERT(endPoint != 0); // bad type
                        _item = new SwpSimEndPointGraphicItem(
                            endPoint);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[endPoint->id()] = _item->id();
                        break;
                    }
                    case SWP_MERGE_ITEM:
                    {
                        SwpMergeGraphicItem* merge =
                            dynamic_cast<SwpMergeGraphicItem*>(item);
                        Q_ASSERT(merge != 0); // bad type
                        _item = new SwpSimMergeGraphicItem(
                            merge);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[merge->id()] = _item->id();
                        break;
                    }
                    case SWP_ACTIVITY_CONNECTOR_ITEM:
                    {
                        SwpActivityConnectorGraphicItem* connector =
                            dynamic_cast<SwpActivityConnectorGraphicItem*>(
                                item);
                        Q_ASSERT(connector != 0); // bad type
                        _item =
                            new SwpSimActivityConnectorGraphicItem(
                                connector);
                        simItem = dynamic_cast<ISimItem* >(_item);
                        idMapping[connector->id()] = _item->id();
                        break;
                    }
                    default:
                        Q_ASSERT(false); // bad type
                        break;
                }

                m_simData->addGraphicItem(_item);

                const QList<ConnectionData> connections = data->connections();

                foreach (const ConnectionData& connection, connections)
                {
                    m_simData->makeConnection(CONNECTION_ACTIVITY_SIM,
                        idMapping[connection.Connector->id()],
                        idMapping[connection.From->id()],
                        idMapping[connection.To->id()]);
                }
            }

            foreach (const SimValue& item,
                simActivitiesMapping.values())
            {
                if (!item.second)
                {
                    delete item.first;
                }
            }
        }

        m_simData->setIgnoreSnapFlag(false);

        QSharedPointer<SwpProjectDocument> project =
            qSharedPointerDynamicCast<SwpProjectDocument>(container());

        if (!project.isNull())
        {
            project->linksUpdated();
        }
    }
}

// private slots

void SwpSimulationCaseDocument::handleValidChange(bool valid)
{
    setValid(valid);
}
